#include "face_app.h"
#include "event_app.h"
#include "basic_app.h"
#include "sound_app.h"
#include "memroy_app.h"
#include "finger_app.h"
#include "irq_contorl.h"
#include "safety_board.h"
#include "cardholder_api.h"
#include "device_parameter.h"

#if _SAFETY_VERIFYFUNCTION_ENABLE_
/**
 * @brief 配置电源控制引脚
 *
 */
static void SafetyPwrPinConfiguration(void);

/**
 * @brief 配置中断引脚
 *
 */
static void SafetyIrqPinConfiguration(void);

/**
 * @brief 配置管脚为低功耗模式
 *
 */
static void SafetyPinConfigLowPowerMode(void);

/**
 * @brief 配置管脚为正常模式
 *
 */
static void SafetyPinConfigNormalMode(void);

/**
 * @brief 外部验证模组管脚初始化
 *
 */
static void SafetyPinConfiguration(void);

/**
 * @brief 读取外部验证模组中断管脚电平
 *
 * @return bool - 管脚电平（true：高电平 false：低电平）
 */
static bool SafetyReadIrqnPinLevel(void);

/**
 * @brief 设置电源控制管脚为高电平
 *
 */
static void SafetySetPowerContorHighLevel(void);

/**
 * @brief 设置电源控制管脚为低电平
 *
 */
static void SafetySetPowerContorLowLevel(void);

/**
 * @brief 获取中断管脚电平
 *
 * @return bool - 中断管脚电平（true：高电平 false：低电平）
 */
static bool SafetyGetIrqPinLevel(void);

/**
 * @brief 获取中断触发标志
 *
 * @return bool - 中断使能标志（true：触发 false：静默）
 */
static bool SafetyReadItFlagBit(void);

/**
 * @brief 清空中断标志
 *
 */
static void SafetyClearItFlagBit(void);

/**
 * @brief 串口发送
 *
 * @param pDataIn - 数据
 * @param SizeIn  - 数据发送长度
 */
static void SafetyUartSendString(uint8_t *pDataIn, uint16_t SizeIn);

/**
 * @brief 唤醒中断回调
 *
 * @return bool - 中断有效标志（true：有效 false：静默）
 */
static bool SafetyIrqTiggerCallback(void);

/**
 * @brief 事件处理回调
 *
 */
static void SafetyEventHandlerCallback(void);

/**
 * @brief 外部验证模式事件任务回调
 *
 */
static uint16_t SafetyEventTaskCallback(uint8_t TaskId, uint16_t Events);

static uint8_t SafetyEventTaskId = 0;
static bool SafetyIrqTiggerEn = false;
static bool SafetyDataReciveEn = false;
static IrqControl_t SafetyIrqContorlNode = {0};
static EventHandlerTable_t SafetyEventHandlerTable = {0};
static SafetyDataPacket_t *SafetyMessageDataPacket = NULL;
static SafetyExternFunctionTable_t SafetyExternFunctionTable = {0};

static void SafetyPwrPinConfiguration(void)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  GPIOA_ModeCfg(SAFETY_POWER_CONTORL_PIN, GPIO_ModeOut_PP_5mA);

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  GPIOA_ModeCfg(SAFETY_POWER_CONTORL_PIN, GPIO_ModeOut_PP_5mA);

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  GPIOB_ModeCfg(SAFETY_POWER_CONTORL_PIN, GPIO_ModeOut_PP_5mA);

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  GPIOA_ModeCfg(SAFETY_POWER_CONTORL_PIN, GPIO_ModeOut_PP_5mA);
#endif
}

static void SafetyIrqPinConfiguration(void)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  GPIOA_ModeCfg(SAFETY_EVENT_IRQN_PIN, GPIO_ModeIN_PD);
  GPIOA_ITModeCfg(SAFETY_EVENT_IRQN_PIN, GPIO_ITMode_RiseEdge);
  PFIC_EnableIRQ(GPIO_A_IRQn);

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  GPIOA_ModeCfg(SAFETY_EVENT_IRQN_PIN, GPIO_ModeIN_PD);
  GPIOA_ITModeCfg(SAFETY_EVENT_IRQN_PIN, GPIO_ITMode_RiseEdge);
  PFIC_EnableIRQ(GPIO_A_IRQn);

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  GPIOB_ModeCfg(SAFETY_EVENT_IRQN_PIN, GPIO_ModeIN_PD);
  GPIOB_ITModeCfg(SAFETY_EVENT_IRQN_PIN, GPIO_ITMode_RiseEdge);
  PFIC_EnableIRQ(GPIO_B_IRQn);

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  GPIOA_ModeCfg(SAFETY_EVENT_IRQN_PIN, GPIO_ModeIN_PD);
  GPIOA_ITModeCfg(SAFETY_EVENT_IRQN_PIN, GPIO_ITMode_RiseEdge);
  PFIC_EnableIRQ(GPIO_A_IRQn);
#endif

  PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_GPIO_WAKE, Long_Delay);
  AddIrqNewTable(&SafetyIrqContorlNode, SafetyIrqTiggerCallback);
}

static void SafetyPinConfigLowPowerMode(void)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  R8_UART3_MCR = 0x00;
  R8_UART3_IER = 0x00;
  R8_UART3_FCR = 0x00;
  R8_UART3_LCR = 0x00;
  R8_UART3_IIR = 0x01;
  R8_UART3_LSR = 0x60;
  R8_UART3_RFC = 0x00;
  R8_UART3_TFC = 0x00;

  UART3_INTCfg(DISABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
  PFIC_DisableIRQ(UART3_IRQn);

  GPIOA_ModeCfg(SAFETY_UART_RXD_PIN, GPIO_ModeOut_PP_5mA);
  GPIOA_ModeCfg(SAFETY_UART_TXD_PIN, GPIO_ModeOut_PP_5mA);

  GPIOA_ResetBits(SAFETY_UART_RXD_PIN);
  GPIOA_ResetBits(SAFETY_UART_TXD_PIN);

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  R8_UART3_MCR = 0x00;
  R8_UART3_IER = 0x00;
  R8_UART3_FCR = 0x00;
  R8_UART3_LCR = 0x00;
  R8_UART3_IIR = 0x01;
  R8_UART3_LSR = 0x60;
  R8_UART3_RFC = 0x00;
  R8_UART3_TFC = 0x00;

  UART3_INTCfg(DISABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
  PFIC_DisableIRQ(UART3_IRQn);

  GPIOA_ModeCfg(SAFETY_UART_RXD_PIN, GPIO_ModeOut_PP_5mA);
  GPIOA_ModeCfg(SAFETY_UART_TXD_PIN, GPIO_ModeOut_PP_5mA);

  GPIOA_ResetBits(SAFETY_UART_RXD_PIN);
  GPIOA_ResetBits(SAFETY_UART_TXD_PIN);

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  R8_UART3_MCR = 0x00;
  R8_UART3_IER = 0x00;
  R8_UART3_FCR = 0x00;
  R8_UART3_LCR = 0x00;
  R8_UART3_IIR = 0x01;
  R8_UART3_LSR = 0x60;
  R8_UART3_RFC = 0x00;
  R8_UART3_TFC = 0x00;

  UART3_INTCfg(DISABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
  PFIC_DisableIRQ(UART3_IRQn);

  GPIOPinRemap(DISABLE, RB_PIN_UART3);
  GPIOB_ModeCfg(SAFETY_UART_RXD_PIN, GPIO_ModeOut_PP_5mA);
  GPIOB_ModeCfg(SAFETY_UART_TXD_PIN, GPIO_ModeOut_PP_5mA);

  GPIOB_ResetBits(SAFETY_UART_RXD_PIN);
  GPIOB_ResetBits(SAFETY_UART_TXD_PIN);

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  R8_UART0_MCR = 0x00;
  R8_UART0_IER = 0x00;
  R8_UART0_FCR = 0x00;
  R8_UART0_LCR = 0x00;
  R8_UART0_IIR = 0x01;
  R8_UART0_LSR = 0x60;
  R8_UART0_RFC = 0x00;
  R8_UART0_TFC = 0x00;

  UART0_INTCfg(DISABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
  PFIC_DisableIRQ(UART0_IRQn);

  GPIOPinRemap(DISABLE, RB_PIN_UART0);
  GPIOA_ModeCfg(SAFETY_UART_RXD_PIN, GPIO_ModeOut_PP_5mA);
  GPIOA_ModeCfg(SAFETY_UART_TXD_PIN, GPIO_ModeOut_PP_5mA);

  GPIOA_ResetBits(SAFETY_UART_RXD_PIN);
  GPIOA_ResetBits(SAFETY_UART_TXD_PIN);
#endif
}

static void SafetyPinConfigNormalMode(void)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  GPIOA_SetBits(SAFETY_UART_TXD_PIN);
  GPIOA_ModeCfg(SAFETY_UART_RXD_PIN, GPIO_ModeIN_PU);
  GPIOA_ModeCfg(SAFETY_UART_TXD_PIN, GPIO_ModeOut_PP_5mA);

  UART3_DefInit();
  UART3_BaudRateCfg(SAFETY_UART_BAUD_RATE);
  UART3_ByteTrigCfg(UART_7BYTE_TRIG);
  UART3_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
  PFIC_EnableIRQ(UART3_IRQn);

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  GPIOA_SetBits(SAFETY_UART_TXD_PIN);
  GPIOA_ModeCfg(SAFETY_UART_RXD_PIN, GPIO_ModeIN_PU);
  GPIOA_ModeCfg(SAFETY_UART_TXD_PIN, GPIO_ModeOut_PP_5mA);

  UART3_DefInit();
  UART3_BaudRateCfg(SAFETY_UART_BAUD_RATE);
  UART3_ByteTrigCfg(UART_7BYTE_TRIG);
  UART3_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
  PFIC_EnableIRQ(UART3_IRQn);

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  GPIOPinRemap(ENABLE, RB_PIN_UART3);
  GPIOB_SetBits(SAFETY_UART_TXD_PIN);
  GPIOB_ModeCfg(SAFETY_UART_RXD_PIN, GPIO_ModeIN_PU);

  UART3_DefInit();
  UART3_BaudRateCfg(SAFETY_UART_BAUD_RATE);
  UART3_ByteTrigCfg(UART_7BYTE_TRIG);
  UART3_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
  PFIC_EnableIRQ(UART3_IRQn);

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  GPIOPinRemap(ENABLE, RB_PIN_UART0);
  GPIOA_SetBits(SAFETY_UART_TXD_PIN);
  GPIOA_ModeCfg(SAFETY_UART_RXD_PIN, GPIO_ModeIN_PU);
  GPIOA_ModeCfg(SAFETY_UART_TXD_PIN, GPIO_ModeOut_PP_5mA);

  UART0_DefInit();
  UART0_BaudRateCfg(SAFETY_UART_BAUD_RATE);
  UART0_ByteTrigCfg(UART_7BYTE_TRIG);
  UART0_INTCfg(ENABLE, RB_IER_RECV_RDY | RB_IER_LINE_STAT);
  PFIC_EnableIRQ(UART0_IRQn);
#endif
}

static void SafetyPinConfiguration(void)
{
  SafetyPwrPinConfiguration();
  SafetyIrqPinConfiguration();
  SafetyPinConfigLowPowerMode();
  SafetySetPowerContorLowLevel();
}

static bool SafetyReadIrqnPinLevel(void)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  if (GPIOA_ReadPortPin(SAFETY_EVENT_IRQN_PIN) == SAFETY_EVENT_IRQN_PIN)
    return true;

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  if (GPIOA_ReadPortPin(SAFETY_EVENT_IRQN_PIN) == SAFETY_EVENT_IRQN_PIN)
    return true;

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  if (GPIOB_ReadPortPin(SAFETY_EVENT_IRQN_PIN) == SAFETY_EVENT_IRQN_PIN)
    return true;

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  if (GPIOA_ReadPortPin(SAFETY_EVENT_IRQN_PIN) == SAFETY_EVENT_IRQN_PIN)
    return true;
#endif

  return false;
}

static void SafetySetPowerContorHighLevel(void)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  GPIOA_SetBits(SAFETY_POWER_CONTORL_PIN);

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  GPIOA_SetBits(SAFETY_POWER_CONTORL_PIN);

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  GPIOB_SetBits(SAFETY_POWER_CONTORL_PIN);

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  GPIOA_SetBits(SAFETY_POWER_CONTORL_PIN);
#endif
}

static void SafetySetPowerContorLowLevel(void)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  GPIOA_ResetBits(SAFETY_POWER_CONTORL_PIN);

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  GPIOA_ResetBits(SAFETY_POWER_CONTORL_PIN);

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  GPIOB_ResetBits(SAFETY_POWER_CONTORL_PIN);

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  GPIOA_ResetBits(SAFETY_POWER_CONTORL_PIN);
#endif
}

static bool SafetyGetIrqPinLevel(void)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  if (GPIOA_ReadPortPin(SAFETY_EVENT_IRQN_PIN) == SAFETY_EVENT_IRQN_PIN)
    return true;

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  if (GPIOA_ReadPortPin(SAFETY_EVENT_IRQN_PIN) == SAFETY_EVENT_IRQN_PIN)
    return true;

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  if (GPIOB_ReadPortPin(SAFETY_EVENT_IRQN_PIN) == SAFETY_EVENT_IRQN_PIN)
    return true;

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  if (GPIOA_ReadPortPin(SAFETY_EVENT_IRQN_PIN) == SAFETY_EVENT_IRQN_PIN)
    return true;
#endif

  return false;
}

static void SafetyEnableIrq(void)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  R16_PA_INT_EN |= SAFETY_EVENT_IRQN_PIN;
  GPIOA_ClearITFlagBit(SAFETY_EVENT_IRQN_PIN);

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  R16_PA_INT_EN |= SAFETY_EVENT_IRQN_PIN;
  GPIOA_ClearITFlagBit(SAFETY_EVENT_IRQN_PIN);

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  R16_PB_INT_EN |= SAFETY_EVENT_IRQN_PIN;
  GPIOB_ClearITFlagBit(SAFETY_EVENT_IRQN_PIN);

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  R16_PA_INT_EN |= SAFETY_EVENT_IRQN_PIN;
  GPIOA_ClearITFlagBit(SAFETY_EVENT_IRQN_PIN);
#endif
}

static void SafetyDisableIrq(void)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  R16_PA_INT_EN &= ~SAFETY_EVENT_IRQN_PIN;
  GPIOA_ClearITFlagBit(SAFETY_EVENT_IRQN_PIN);

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  R16_PA_INT_EN &= ~SAFETY_EVENT_IRQN_PIN;
  GPIOA_ClearITFlagBit(SAFETY_EVENT_IRQN_PIN);

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  R16_PB_INT_EN &= ~SAFETY_EVENT_IRQN_PIN;
  GPIOB_ClearITFlagBit(SAFETY_EVENT_IRQN_PIN);

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  R16_PA_INT_EN &= ~SAFETY_EVENT_IRQN_PIN;
  GPIOA_ClearITFlagBit(SAFETY_EVENT_IRQN_PIN);
#endif
}

static bool SafetyReadItFlagBit(void)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  if (GPIOA_ReadITFlagBit(SAFETY_EVENT_IRQN_PIN) == SAFETY_EVENT_IRQN_PIN)
    return true;

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  if (GPIOA_ReadITFlagBit(SAFETY_EVENT_IRQN_PIN) == SAFETY_EVENT_IRQN_PIN)
    return true;

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  if (GPIOB_ReadITFlagBit(SAFETY_EVENT_IRQN_PIN) == SAFETY_EVENT_IRQN_PIN)
    return true;

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  if (GPIOA_ReadITFlagBit(SAFETY_EVENT_IRQN_PIN) == SAFETY_EVENT_IRQN_PIN)
    return true;
#endif

  return false;
}

static void SafetyClearItFlagBit(void)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  GPIOA_ClearITFlagBit(SAFETY_EVENT_IRQN_PIN);

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  GPIOA_ClearITFlagBit(SAFETY_EVENT_IRQN_PIN);

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  GPIOB_ClearITFlagBit(SAFETY_EVENT_IRQN_PIN);

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  GPIOA_ClearITFlagBit(SAFETY_EVENT_IRQN_PIN);
#endif
}

static void SafetyUartSendString(uint8_t *pDataIn, uint16_t SizeIn)
{
#if _BOARD_TYPE_ == _V31_A_BOARD_
  UART3_SendString(pDataIn, SizeIn);
  while ((R8_UART3_LSR & RB_LSR_TX_ALL_EMP) == 0)
  {
    __nop();
  }

#elif _BOARD_TYPE_ == _V33_A_BOARD_
  UART3_SendString(pDataIn, SizeIn);
  while ((R8_UART3_LSR & RB_LSR_TX_ALL_EMP) == 0)
  {
    __nop();
  }

#elif _BOARD_TYPE_ == _V33_B_BOARD_
  UART3_SendString(pDataIn, SizeIn);
  while ((R8_UART3_LSR & RB_LSR_TX_ALL_EMP) == 0)
  {
    __nop();
  }

#elif _BOARD_TYPE_ == _V33_C_BOARD_
  UART0_SendString(pDataIn, SizeIn);
  while ((R8_UART0_LSR & RB_LSR_TX_ALL_EMP) == 0)
  {
    __nop();
  }
#endif
}

static bool SafetyIrqTiggerCallback(void)
{
  if (SafetyReadItFlagBit() == true)
  {
    SafetyClearItFlagBit();

    SafetyIrqTiggerEn = true;
    return true;
  }

  return false;
}

static void SafetyEventHandlerCallback(void)
{
  if (SafetyIrqTiggerEn == true)
  {
    SafetyIrqTiggerEn = false;

    SafetyDelayMs(20);
    if (SafetyGetIrqPinLevel() == true)
    {
      if (SafetyExternFunctionTable.EventWakeupCallback != NULL)
      {
        SafetyExternFunctionTable.EventWakeupCallback();
      }
    }
  }

  if (SafetyDataReciveEn == true)
  {
    SafetyDataReciveEn = false;

    if (SafetyExternFunctionTable.UartRxDoneCallBack != NULL)
    {
      SafetyExternFunctionTable.UartRxDoneCallBack();
    }
  }
}

__INTERRUPT
__HIGH_CODE
#if _BOARD_TYPE_ == _V31_A_BOARD_
void UART3_IRQHandler(void)
{
  switch (UART3_GetITFlag())
  {
  case UART_II_LINE_STAT:
  {
    UART3_GetLinSTA(); // @suppress("Statement has no effect")
  }
  break;

  case UART_II_RECV_RDY:
  {
    uint8_t WirelessUartRxData = UART3_RecvByte();
    if (SafetyMessageDataPacket != NULL)
    {
      if (SafetyMessageDataPacket->DataSize < SAFETY_MESSAGE_PACKET_LENGTH)
      {
        SafetyMessageDataPacket->DataBuff[SafetyMessageDataPacket->DataSize++] = WirelessUartRxData;
      }
    }
  }
  break;

  case UART_II_RECV_TOUT:
  {
    uint8_t TmpDataCount = 0, TmpDataBuff[8] = {0};

    TmpDataCount = UART3_RecvString(TmpDataBuff);
    if (SafetyMessageDataPacket != NULL)
    {
      if ((SafetyMessageDataPacket->DataSize + TmpDataCount) < SAFETY_MESSAGE_PACKET_LENGTH)
      {
        memcpy(&SafetyMessageDataPacket->DataBuff[SafetyMessageDataPacket->DataSize], TmpDataBuff, TmpDataCount);
        SafetyMessageDataPacket->DataSize += TmpDataCount;
      }
    }

    SafetyDataReciveEn = true;
  }
  break;
  }
}

#elif _BOARD_TYPE_ == _V33_A_BOARD_
void UART3_IRQHandler(void)
{
  switch (UART3_GetITFlag())
  {
  case UART_II_LINE_STAT:
  {
    UART3_GetLinSTA(); // @suppress("Statement has no effect")
  }
  break;

  case UART_II_RECV_RDY:
  {
    uint8_t WirelessUartRxData = UART3_RecvByte();
    if (SafetyMessageDataPacket != NULL)
    {
      if (SafetyMessageDataPacket->DataSize < SAFETY_MESSAGE_PACKET_LENGTH)
      {
        SafetyMessageDataPacket->DataBuff[SafetyMessageDataPacket->DataSize++] = WirelessUartRxData;
      }
    }
  }
  break;

  case UART_II_RECV_TOUT:
  {
    uint8_t TmpDataCount = 0, TmpDataBuff[8] = {0};

    TmpDataCount = UART3_RecvString(TmpDataBuff);
    if (SafetyMessageDataPacket != NULL)
    {
      if ((SafetyMessageDataPacket->DataSize + TmpDataCount) < SAFETY_MESSAGE_PACKET_LENGTH)
      {
        memcpy(&SafetyMessageDataPacket->DataBuff[SafetyMessageDataPacket->DataSize], TmpDataBuff, TmpDataCount);
        SafetyMessageDataPacket->DataSize += TmpDataCount;
      }
    }

    SafetyDataReciveEn = true;
  }
  break;
  }
}

#elif _BOARD_TYPE_ == _V33_B_BOARD_
void UART3_IRQHandler(void)
{
  switch (UART3_GetITFlag())
  {
  case UART_II_LINE_STAT:
  {
    UART3_GetLinSTA(); // @suppress("Statement has no effect")
  }
  break;

  case UART_II_RECV_RDY:
  {
    uint8_t WirelessUartRxData = UART3_RecvByte();
    if (SafetyMessageDataPacket != NULL)
    {
      if (SafetyMessageDataPacket->DataSize < SAFETY_MESSAGE_PACKET_LENGTH)
      {
        SafetyMessageDataPacket->DataBuff[SafetyMessageDataPacket->DataSize++] = WirelessUartRxData;
      }
    }
  }
  break;

  case UART_II_RECV_TOUT:
  {
    uint8_t TmpDataCount = 0, TmpDataBuff[8] = {0};

    TmpDataCount = UART3_RecvString(TmpDataBuff);
    if (SafetyMessageDataPacket != NULL)
    {
      if ((SafetyMessageDataPacket->DataSize + TmpDataCount) < SAFETY_MESSAGE_PACKET_LENGTH)
      {
        memcpy(&SafetyMessageDataPacket->DataBuff[SafetyMessageDataPacket->DataSize], TmpDataBuff, TmpDataCount);
        SafetyMessageDataPacket->DataSize += TmpDataCount;
      }
    }

    SafetyDataReciveEn = true;
  }
  break;
  }
}

#elif _BOARD_TYPE_ == _V33_C_BOARD_
void UART0_IRQHandler(void)
{
  switch (UART0_GetITFlag())
  {
  case UART_II_LINE_STAT:
  {
    UART0_GetLinSTA(); // @suppress("Statement has no effect")
  }
  break;

  case UART_II_RECV_RDY:
  {
    uint8_t WirelessUartRxData = UART0_RecvByte();
    if (SafetyMessageDataPacket != NULL)
    {
      if (SafetyMessageDataPacket->DataSize < SAFETY_MESSAGE_PACKET_LENGTH)
      {
        SafetyMessageDataPacket->DataBuff[SafetyMessageDataPacket->DataSize++] = WirelessUartRxData;
      }
    }
  }
  break;

  case UART_II_RECV_TOUT:
  {
    uint8_t TmpDataCount = 0, TmpDataBuff[8] = {0};

    TmpDataCount = UART0_RecvString(TmpDataBuff);
    if (SafetyMessageDataPacket != NULL)
    {
      if ((SafetyMessageDataPacket->DataSize + TmpDataCount) < SAFETY_MESSAGE_PACKET_LENGTH)
      {
        memcpy(&SafetyMessageDataPacket->DataBuff[SafetyMessageDataPacket->DataSize], TmpDataBuff, TmpDataCount);
        SafetyMessageDataPacket->DataSize += TmpDataCount;
      }
    }

    SafetyDataReciveEn = true;
  }
  break;
  }
}
#endif

static uint16_t SafetyEventTaskCallback(uint8_t TaskId, uint16_t Events)
{
  if (TaskId == SafetyEventTaskId)
  {
    if (Events & SAFETY_COMMAND_OPERATION)
    {
      if (SafetyExternFunctionTable.CommandOperationCallback != NULL)
      {
        SafetyExternFunctionTable.CommandOperationCallback();
      }

      return (Events ^ SAFETY_COMMAND_OPERATION);
    }
  }

  return 0;
}

void SafetyDelayMs(uint16_t Ms)
{
  DelayMs(Ms);
}

void SafetySetPowerContorlPinLevel(bool PinLevel)
{
  (PinLevel == true) ? SafetySetPowerContorHighLevel() : SafetySetPowerContorLowLevel();
}

bool SafetyGetIrqnPinLevel(void)
{
  return SafetyReadIrqnPinLevel();
}

bool SafetyUartSendData(uint8_t *pDataIn, uint16_t SizeIn)
{
  if (pDataIn != NULL)
  {
    if (SizeIn > 0)
    {
      SafetyUartSendString(pDataIn, SizeIn);
      return true;
    }
  }

  return false;
}

uint8_t SafetyGetTheNumberOfRegisteredUsers(void)
{
  uint8_t NumberOfRegister = 0;

#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  NumberOfRegister = FaceGetTheNumberOfRegisteredUsers();

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
  NumberOfRegister = FingerGetTheNumberOfRegisteredUsers();
#endif

  return NumberOfRegister;
}

void SafetyGetDeviceSerialNumber(char *pSerialNumberOut)
{
#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  FaceGetDeviceSerialNumber(pSerialNumberOut);

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
  FingerGetDeviceSerialNumber(pSerialNumberOut);
#endif
}

void SafetyGetApplicationVersion(char *pVersionOut)
{
#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  FaceGetApplicationVersion(pVersionOut);

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
  FingerGetApplicationVersion(pVersionOut);
#endif
}

void SafetyGetAlgorithmVersion(char *pVersionOut)
{
#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  FaceGetAlgorithmVersion(pVersionOut);
#endif
}

void SafetyReportgSeltTestResult(SafetyCommandExecuteResult_t Result)
{
  bool SeltTestResult = (Result == SAFETY_COMMAND_SUCCESS) ? true : false;
  EventMarkingModuleSelfTestResults(SAFETY_MODULE_DEV_SELF_TEST, SeltTestResult);
}

void SafetyNotificationResetResults(SafetyCommandExecuteResult_t Result)
{
  bool ResetResult = (Result == SAFETY_COMMAND_SUCCESS) ? true : false;
  EventMarkingModuleResetResult(DELETE_SAFETY_MODULE_DATA, ResetResult);
}

bool SafetyNotificationGetEigenvalueFileResult(SafetyCommandExecuteResult_t Result)
{
  return false;
}

bool SafetyReportLocalRegisterKeyResult(SafetyCommandExecuteResult_t Result)
{
  uint16_t RegisterUserId = 0;
  uint8_t NumberOfKey = 0, KeyValue[2] = {0};
  EventKeyType_t RegisterKeyType = KEY_TYEP_UNKOWN;
  LocalRegisterResult_t UserRegisterResult = LOCAL_REGISTER_RESULT_ERROR;

#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  RegisterKeyType = KEY_TYPE_FACE;
  RegisterUserId = FaceGetLocalRegisterUserId();

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
  RegisterKeyType = KEY_TYPE_FINGER;
  RegisterUserId = FingerGetLocalRegisterUserId();
#endif

  switch (Result)
  {
  case SAFETY_COMMAND_SUCCESS:
    UserRegisterResult = LOCAL_REGISTER_RESULT_WAIT_SAVE;

    KeyValue[NumberOfKey++] = (uint8_t)((RegisterUserId & 0xFF00) >> 8);
    KeyValue[NumberOfKey++] = (uint8_t)(RegisterUserId & 0x00FF);
    break;

  case SAFETY_COMMAND_USER_IS_FULL:
    UserRegisterResult = LOCAL_REGISTER_RESULT_SAFETY_USER_IS_FULL;
    break;

  case SAFETY_COMMAND_USER_ALREADY_EXISTS:
    UserRegisterResult = LOCAL_REGISTER_RESULT_KEY_ALREADY_EXISTS;
    break;

  default:
    UserRegisterResult = LOCAL_REGISTER_RESULT_ERROR;
    break;
  }

  EventUpdateLocalRegisterKeyResult(UserRegisterResult);
  if (Result == SAFETY_COMMAND_SUCCESS)
    return EventExitLocalRegisterKeyTask(RegisterKeyType, KeyValue, NumberOfKey);

  return EventExitLocalRegisterKeyTask(RegisterKeyType, NULL, 0);
}

bool SafertReportOnlineRegisterKeyResult(SafetyCommandExecuteResult_t Result)
{
  uint16_t RegisterUserId = 0;
  uint8_t NumberOfKey = 0, KeyType = 0, KeyValue[2] = {0};

#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  KeyType = FACE_ID_AUTHENTICATION;
  RegisterUserId = FaceGetLocalRegisterUserId();

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
  KeyType = FINGER_PRINTF_AUTHENTICATION;
  RegisterUserId = FingerGetLocalRegisterUserId();
#endif

  PRINT("[safety]: register user id = %d\r\n", RegisterUserId);
  switch (Result)
  {
  case SAFETY_COMMAND_SUCCESS:
    EventUpdateOnlineRegisterResult(REGISTER_USER_SUCCESS_WAIT_SAVE);

    KeyValue[NumberOfKey++] = (uint8_t)((RegisterUserId & 0xFF00) >> 8);
    KeyValue[NumberOfKey++] = (uint8_t)(RegisterUserId & 0x00FF);
    break;

  case SAFETY_COMMAND_USER_IS_FULL:
    EventUpdateOnlineRegisterResult(REGISTER_SAFETY_USER_IS_FULL);
    break;

  case SAFETY_COMMAND_USER_ALREADY_EXISTS:
    EventUpdateOnlineRegisterResult(REGISTER_USER_KEY_ALREADY_EXISTS);
    break;

  default:
    EventUpdateOnlineRegisterResult(REGISTER_USER_ERROR);
    break;
  }

  EventExitOnlineRegisterTask(KeyType, KeyValue, NumberOfKey);

  return false;
}

bool SafetyReportUserAuthenticationResult(SafetyCommandExecuteResult_t Result)
{
  uint16_t AuthenticationUserId = 0;
  uint8_t NumberOfKey = 0, KeyType = 0, KeyValue[2] = {0};

#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  KeyType = KEY_TYPE_FACE;
  AuthenticationUserId = FaceGetAuthorizedUserCode();

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
  KeyType = KEY_TYPE_FINGER;
  AuthenticationUserId = FingerGetAuthorizedUserCode();
#endif

  KeyValue[NumberOfKey++] = (uint8_t)((AuthenticationUserId & 0xFF00) >> 8);
  KeyValue[NumberOfKey++] = (uint8_t)(AuthenticationUserId & 0x00FF);
  if (Result == SAFETY_COMMAND_SUCCESS)
  {
    if (EventGetVerifyNormalOpenPermissionTaskStartEn() == true)
      return EventExitVerifyNormalOpenPermissionTask(KeyType, KeyValue, NumberOfKey);

    return EventExitExternalModuleVerificationTask(KeyType, KeyValue, NumberOfKey);
  }
  else
  {
    if (EventGetVerifyNormalOpenPermissionTaskStartEn() != true)
      return EventExitExternalModuleVerificationTask(KeyType, NULL, 0);
  }

  return false;
}

void SafetyExitOnlineRegisterListerTask(void)
{
}

void SafetyCommunicationsInitialization(void)
{
#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  FaceFunctionalInitialization();

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
  FingerFunctionalInitialization();
#endif
}

void SafetyForcedToGotoSleepInitialization(void)
{
#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  FaceStartForcedToGotoSleep();

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
  FingerStartForcedToGotoSleep();
#endif
}

void SafetyStartLocalRegisterTask(uint8_t WaitTime)
{
#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  FaceStartLocalRegisterTasks(WaitTime);

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
  FingerStartLocalRegisterTasks(WaitTime);
#endif
}

void SafetyStartAuthenticationTask(void)
{
#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  FaceStartUserAuthenticationTasks();

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
#endif
}

void SafetyFlaggingTargetUsersToGetFeatureValueFiles(uint16_t UserId)
{
#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  FaceMarkUserToGetEigenvalueFile(UserId);

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
#endif
}

void SafetyPreparationBeforeDeletingUser(void)
{
#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  FaceStartDeleteUserTasks();

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
#endif
}

void SafetyRecordUsersToBeDeleted(uint16_t UserId)
{
#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  FaceRecordUsersToBeDeleted(UserId);

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
#endif
}

bool SafetyVerifyMessageValidity(uint8_t *pMessageIn, uint8_t *pDataOffsetOut, uint16_t *pDataSizeOut, uint8_t *pResultOut)
{
  uint8_t VerificationStatus = false;

#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  VerificationStatus = FaceVerifyMessageValidity(pMessageIn, pDataOffsetOut, pDataSizeOut, pResultOut);

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
  VerificationStatus = FingerValidateMessage(pMessageIn, pDataOffsetOut, pDataSizeOut, pResultOut);
#endif

  return VerificationStatus;
}

void SafetyEnableInterrupts(void)
{
  SafetyEnableIrq();
}

void SafetyDisableInterrupts(void)
{
  SafetyDisableIrq();
}

void SafetyConfigurationLowPower(void)
{
  SafetyPinConfigLowPowerMode();
}

void SafetyConfigurationNormalMode(void)
{
  SafetyPinConfigNormalMode();
}

void SafetyStopCommandOperationTask(void)
{
  tmos_stop_task(SafetyEventTaskId, SAFETY_COMMAND_OPERATION);
}

void SafetyDelayedStartCommandOperationTask(uint32_t Ms)
{
  tmos_stop_task(SafetyEventTaskId, SAFETY_COMMAND_OPERATION);
  tmos_start_task(SafetyEventTaskId, SAFETY_COMMAND_OPERATION, MS1_TO_SYSTEM_TIME(Ms));
}

void SafetyStartCommandOperationTaskNoWait(void)
{
  tmos_stop_task(SafetyEventTaskId, SAFETY_COMMAND_OPERATION);
  tmos_set_event(SafetyEventTaskId, SAFETY_COMMAND_OPERATION);
}

void SafetyBoardBoardInitialisation(SafetyTaskApi_t *pTaskApiOut, SafetyDataPacket_t *pDataPacket, SafetyExternFunctionTable_t *pExternFunctionIn)
{
  SafetyMessageDataPacket = pDataPacket;
  SafetyExternFunctionTable.UartRxDoneCallBack = pExternFunctionIn->UartRxDoneCallBack;
  SafetyExternFunctionTable.EventWakeupCallback = pExternFunctionIn->EventWakeupCallback;
  SafetyExternFunctionTable.CommandOperationCallback = pExternFunctionIn->CommandOperationCallback;

#if _SAFETY_MODULE_TYPE_ == _FACE_SAFETY_MODULE_
  pTaskApiOut->SelfTestCallback.Build = FaceBuildSelfTestMessage;
  pTaskApiOut->FactorySettingCallback.Build = FaceBuildFactorySettingMessage;
  pTaskApiOut->GetEigenvalueFileCallback.Build = FaceBuildGetEigenvalueFileMessage;
  pTaskApiOut->ForcedToGotoSleepCallback.Build = FaceBuildForcedToGotoSleepMessage;
  pTaskApiOut->LocalRegisterUserCallback.Build = FaceBuildLocalRegisterUserMessage;
  pTaskApiOut->IdentifyUserRightsCallback.Build = FaceBuildUserAuthenticationMessage;
  pTaskApiOut->DeletingSpecificUsersCallback.Build = FaceBuildDeletingSpecificUsersMessage;
  pTaskApiOut->RegistrationByEigenvalueCallback.Build = FaceBuildRegistrationByEigenvalueMessage;

  pTaskApiOut->SelfTestCallback.Parsing = FaceParsingSelfTestMessage;
  pTaskApiOut->FactorySettingCallback.Parsing = FaceParsingDeviceFactorySettingMessage;
  pTaskApiOut->ForcedToGotoSleepCallback.Parsing = FaceParsingForcedToGotoSleepMessage;
  pTaskApiOut->GetEigenvalueFileCallback.Parsing = FaceParsingGetEigenvalueFileMessage;
  pTaskApiOut->LocalRegisterUserCallback.Parsing = FaceParsingLocalRegisterUserMessage;
  pTaskApiOut->IdentifyUserRightsCallback.Parsing = FaceParsingUserAuthenticationMessage;
  pTaskApiOut->DeletingSpecificUsersCallback.Parsing = FaceParsingDeletingSpecificUsersMessage;
  pTaskApiOut->RegistrationByEigenvalueCallback.Parsing = FaceParsingRegistrationByEigenvalueMessage;

#elif _SAFETY_MODULE_TYPE_ == _FINGER_SAFETY_MODULE_
  pTaskApiOut->SelfTestCallback.Build = FingerBuildSelfTestMessage;
  pTaskApiOut->FactorySettingCallback.Build = FingerBuildFactorySettingMessage;
  pTaskApiOut->GetEigenvalueFileCallback.Build = FingerBuildGetEigenvalueFileMessage;
  pTaskApiOut->ForcedToGotoSleepCallback.Build = FingerBuildForcedToGotoSleepMessage;
  pTaskApiOut->LocalRegisterUserCallback.Build = FingerBuildLocalRegisterUserMessage;
  pTaskApiOut->IdentifyUserRightsCallback.Build = FingerBuildUserAuthenticationMessage;
  pTaskApiOut->DeletingSpecificUsersCallback.Build = FingerBuildDeletingSpecificUsersMessage;
  pTaskApiOut->RegistrationByEigenvalueCallback.Build = FingerBuildRegistrationByEigenvalueMessage;

  pTaskApiOut->SelfTestCallback.Parsing = FingerParsingSelfTestMessage;
  pTaskApiOut->FactorySettingCallback.Parsing = FingerParsingDeviceFactorySettingMessage;
  pTaskApiOut->ForcedToGotoSleepCallback.Parsing = FingerParsingForcedToGotoSleepMessage;
  pTaskApiOut->GetEigenvalueFileCallback.Parsing = FingerParsingGetEigenvalueFileMessage;
  pTaskApiOut->LocalRegisterUserCallback.Parsing = FingerParsingLocalRegisterMessage;
  pTaskApiOut->IdentifyUserRightsCallback.Parsing = FingerParsingUserAuthenticationMessage;
  pTaskApiOut->DeletingSpecificUsersCallback.Parsing = FingerParsingDeletingSpecificUsersMessage;
  pTaskApiOut->RegistrationByEigenvalueCallback.Parsing = FingerParsingRegistrationByEigenvalueMessage;
#endif

  SafetyPinConfiguration();
  EventAddNewEventHandler(&SafetyEventHandlerTable, SafetyEventHandlerCallback);
  SafetyEventTaskId = TMOS_ProcessEventRegister(SafetyEventTaskCallback);
}

#endif
